#ifndef CLASS_OP_FACTORY
#define CLASS_OP_FACTORY

/**********************************************************************
 * opFactory.h
 * 
 * Descripcion:
 * En esta clase se define la fabrica de operaciones. Esta produce una
 * operacion nueva a partir de un string.
 * Tiene una clase interna llamada manejador, que lo que hace es formar
 * una cadena de llamadas a creacion de operaciones, aprovechando que 
 * cada una sabe como crearse. Si la operacion en turno considera que 
 * los parametros recibidos no coinciden con su formato pasa el manejador
 * a la siguiente operacion en la cadena. Asi hasta que no hayan mas 
 * eslabones, si llega a ese punto y no pudo crearse devuelve una
 * operacion invalida
**********************************************************************/

#include <string>
#include <stdexcept>
#include "operacion.h"
#include "operacionEstadistica.h"
#include "operacionFin.h"
#include "operacionEliminar.h"
#include "operacionCrear.h"
#include "operacionCrearIndSec.h"
#include "operacionConsulta.h"
#include "operacionQuitar.h"
#include "operacionIngresar.h"
#include "operacionActualizar.h"

#define ESTADISTICA	   	0
#define FIN		   		1
#define ELIMINAR		2
#define CREAR			3
#define CONSULTA		4
#define CREAR_IND		5
#define QUITAR			6
#define INGRESAR		7
#define ACTUALIZAR		8

class Fabrica_Operaciones{
	
	public:
		Fabrica_Operaciones();
	
		virtual Operacion* crear_operacion(std::string &param);
	
		virtual ~Fabrica_Operaciones();
	private:
			
		Fabrica_Operaciones(Fabrica_Operaciones &f);
		
		Operacion* obtener_instancia_operacion(char tipo, std::string& param);	
		
		
//<--------CLase interna que se encarga de aplicar el patron chain of 
//   responsability para la implementacion especifica que da esta fabrica ---->
			
		class Manejador_Creacion{
			private:
				//tipo de operacion para llamarla en la fabrica
				char tipo;	
				//siguiente manejador por si hay error
				Manejador_Creacion *siguiente; 
			
				Fabrica_Operaciones * fabrica;
			
			public:
				
				Manejador_Creacion(Fabrica_Operaciones *f, char tipo=0, Manejador_Creacion *siguiente=0){
					this->siguiente = siguiente;
					this->tipo = tipo;			
					this->fabrica = f;
				}
				Operacion* obtener_operacion_nueva(std::string param){
					Operacion *op;
					//trato de crear la operacion
					op = fabrica->obtener_instancia_operacion(this->tipo,param);
					//si no pudo, y devolvio NULL
					if(op == NULL){					
						//paso al siguiente de la lista
						if(this->tiene_siguiente())
							op = siguiente->obtener_operacion_nueva(param);
						else
							//si no tiene siguiente, tiro error de que no existe
							//esa operacion
							throw std::runtime_error("Error - Operacion no valida ");
					}
					//devuelvo la operacion
					return op;
				}
				bool tiene_siguiente(){
					return siguiente != 0;
				}
		};

};

#endif
